#ifndef SANDBOX_DEBUGGER
#define SANDBOX_DEBUGGER
#include "../basic.h"
#include "loader.h"
#include <iostream>
#include <string>
#include <set>
static std::set<qword> breakpoint;
void execute()
{
	while ((special_regs[Flag] & (RUNNING + DEBUG)) && !(special_regs[Flag] & ERROR))
	{
		loader();
		selector();
	}
}
void step()
{
	loader();
	selector();
}
void breakdebug()
{
	while (special_regs[Flag] & (RUNNING + DEBUG) && !(special_regs[Flag] & ERROR))
	{
		loader();
		selector();
		if (breakpoint.find(addr_regs[Code]) != breakpoint.end())
			return;
	}
}
void viewbreaks()
{
	std::cout << "Break Point View:\n";
	for (auto &i : breakpoint)
		printf("%#016llx\n", i);
}
inline void addbreak(char *arg)
{
	breakpoint.insert(std::strtoull(arg, nullptr, 16));
}
inline void removebreak(char *arg)
{
	breakpoint.erase(std::strtoull(arg, nullptr, 16));
}
void print(int argc = 0, char **argv = nullptr)
{
	std::string type, option;
	qword value = 0;
	if (argc < 2)
	{
		if (argv == 0)
		{
			std::cin >> type >> option;
			value = std::stoull(option, nullptr, 16);
		}
		else
		{
			std::cout << "print:View values in the virtual machine.\n"
					  << "Format:print type target\n"
					  << "Usable types:\n"
					  << "ram address:View ram block(256bytes)\n"
					  << "funreg num:View qword regs\n"
					  << "addrreg num:View qword regs\n"
					  << "specreg num:View qword regs\n"
					  << "fltreg num:View float regs\n"
					  << "dreg num:View double regs\n"
					  << "vector num:View Vector regs\n\n"
					  << "Error:Command arguments not enough";
			return;
		}
	}
	else if (argc == 2)
	{
		type = argv[0];
		value = std::stoull(argv[1], nullptr, 16);
	}
	if (type == "ram")
	{
		qword block = value & 0xffffffffffffff00;
		for (int i = 0; i < 256; i++)
		{
			printf("0x%02x ", *(ram + block + i));
			if (i % 16 == 15)
				printf("\n");
		}
	}
	else if (type == "funreg")
		printf("Function Reg : 0x%016llx\n", func_regs[value & 0x07]);
	else if (type == "addrreg")
		printf("Address Reg : 0x%016llx\n", addr_regs[value & 0x07]);
	else if (type == "specreg")
		printf("Special Reg : 0x%016llx\n", special_regs[value & 0x07]);
	else if (type == "fltreg")
		printf("Float Reg : 0x%08x ,Equal to %f\n", *(dword *)(&fregs[value & 0x07]), fregs[value & 0x07]);
	else if (type == "dreg")
		printf("Double Reg : 0x%016llx ,Equal to %lf\n", *(qword *)(&dregs[value & 0x07]), dregs[value & 0x07]);
	else if (type == "vector")
	{
		std::cout << "Vector Reg:\n";
		for (int i = 0; i < 8; i++)
			printf("0x%08x ", vregs[value & 0x0f].dvalues[i]);
		std::cout << std::endl;
	}
	fflush(stdin);
}
static void debugger(int argc = 0, char **argv = nullptr)
{
	std::string operation;
	if (argc == 0)
		std::cin >> operation;
	else
		operation = argv[0];
	if (operation == "print")
	{
		if (argc == 0)
			print();
		else
			print((argc - 1), &argv[1]);
	}
	else if (operation == "add")
		addbreak(argv[1]);
	else if (operation == "view")
		viewbreaks();
	else if (operation == "delete")
		removebreak(argv[1]);
	else if (operation == "step")
		step();
	else if (operation == "execute")
		execute();
	else if (operation == "break")
		breakdebug();
	else if (operation == "help")
		std::cout << "Debugger commands:\n"
		<< "help:View help message.\n"
		<< "execute:Go through the program.\n"
		<< "step:Debug the program step by step.\n"
		<< "break:Run the program to the breakpoint.\n"
		<< "add:Add a breakpoint.\n"
		<< "remove:Delete target breakpoint.\n"
		<< "view:View breakpoints.\n"
		<< "print:View value in RAM and registers.\n"
		<< "quit:Quit the system.\n";
	else if (operation == "quit")
		exit(0);
	else
	{
		std::cout << "Debugger commands:\n"
			<< "help:View help message.\n"
			<< "execute:Go through the program.\n"
			<< "step:Debug the program step by step.\n"
			<< "break:Run the program to the breakpoint.\n"
			<< "add:Add a breakpoint.\n"
			<< "remove:Delete target breakpoint.\n"
			<< "view:View breakpoints.\n"
			<< "print:View value in RAM and registers.\n"
			<< "quit:Quit the system.\n";
		std::cout << "Error:Command not found.\n";
		return;
	}
}
#endif